package com.example.demo.zhoushengwen.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.Entity.ExceptionLogExt;
import com.example.demo.Entity.RequestLogExt;
import com.example.demo.zhoushengwen.exceptionHandling.ExceptionCatch;
import com.example.demo.zhoushengwen.service.ExceptionLogExtService;
import com.example.demo.zhoushengwen.service.RequestLogExtService;
import com.example.demo.zhoushengwen.utils.RequestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.UUID;

@Component
public class RequestInterceptor implements HandlerInterceptor {
    @Autowired
    private RequestLogExtService requestLogExtService;

    @Autowired
    private ExceptionLogExtService exceptionLogExtService;

    @Autowired
    private RequestUtil requestUtil;

    @Autowired
    private ExceptionCatch exceptionCatch;

    private static final Logger logger = LoggerFactory.getLogger(RequestInterceptor.class);

    /**
     * 在请求前调用
     * <p>
     * 3-4题已记录在此方法中
     */


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        try {


            System.out.println("在请求前调用");

            //4、  对客户端调用频率进行限制（如每分钟只能调用100次，超过给客户端抛异常）

            //以下为伪代码，具体说明思路
            /**
             * 1.每当有请求过来后，通过request获取请求者ip地址
             * 2.带着ip地址去redis中查询key值为ip的数据,value值为计数次数
             * 3.缓存中若找不到对应的key值，则新增这条数据，设置1分钟失效，value值为1，返回true继续执行
             * 4.缓存中若找到了这条数据，判断value值是否大于100，大于的话抛异常并返回false，
             * 小于的话对value值进行加1操作，更新缓存数据并返回true
             */


            //3、  所有的用户请求，请求参数等都在服务器被记录
            String requestParam = requestUtil.getRequestBody(request);
            if (!StringUtils.isEmpty(requestParam)) {
                //请求参数到服务器中  为节省时间此处为伪代码：
                //ParametersService.insert(requestParam);
            }


            // 2、  服务器记录Jackson解析的非法字符的错误。
            try {
                if (!StringUtils.isEmpty(requestParam)) {
                    JSONObject.parseObject(requestParam);
                }
                return true;
            } catch (Exception e) {
                ExceptionLogExt ex = new ExceptionLogExt();
                ex.setId(UUID.randomUUID().toString());
                ex.setExceptionJson(requestParam);
                ex.setExceptionMessage(e.getMessage());
                ex.setHappenTime(new Date());


                //请求参数格式异常记录到数据库   （记录到了excetionlogExt表中）
                exceptionLogExtService.insert(ex);
                //请求参数格式异常记录到日志
                logger.error(e.getMessage());
                return false;
            }

        } catch (Exception e) {
            //讲拦截器中出现的异常交给异常捕获器去处理
            exceptionCatch.exception(e);
            return false;
        }
    }

    /**
     * 请求处理后，视图渲染前调用
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) {

        try {


            //1、  服务端记录404的错误
            String url = request.getRequestURI().toString();
            if (response.getStatus() == 404 && !request.getRequestURI().contains("error")) {
                System.out.println("404异常");
                String requestUrl = request.getRequestURL().toString();//得到请求的URL地址
                String queryString = request.getQueryString();//得到请求的URL地址中附带的参数
                String remoteAddr = request.getRemoteAddr();//得到来访者的IP地址
                String remoteHost = request.getRemoteHost();
                int remotePort = request.getRemotePort();
                String remoteUser = request.getRemoteUser();
                String method = request.getMethod();//得到请求URL地址时使用的方法
                String pathInfo = request.getPathInfo();
                String localAddr = request.getLocalAddr();//获取WEB服务器的IP地址
                String localName = request.getLocalName();//获取WEB服务器的主机名

                RequestLogExt r = new RequestLogExt();
                r.setId(UUID.randomUUID().toString());
                r.setIp(remoteAddr);
                r.setUrl(requestUrl);
                r.setMethodName(method);
                //....
                int a = 1 / 0;
                requestLogExtService.insert(r);//记录到数据库（记录到了RequestLogExt表中）
                logger.error(r.toString());//记录到日志
            }

        } catch (Exception e) {
            //讲拦截器中出现的异常交给异常捕获器去处理
            exceptionCatch.exception(e);
        }

    }

    /**
     * 请求结束后被调用（视图渲染后）
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        try {
            System.out.println("请求结束后被调用（视图渲染后）");
        } catch (Exception e) {
            //讲拦截器中出现的异常交给异常捕获器去处理
            exceptionCatch.exception(e);
        }

    }
}